8.3: Mentransfer Data Secara Efisien

Materi:

Mentransfer data merupakan bagian penting dari sebagian besar aplikasi Android, namun hal ini bisa berpengaruh negatif pada daya tahan baterai dan meningkatkan biaya penggunaan data. Penggunaan radio nirkabel untuk mentransfer data berpotensi menjadi salah satu sumber paling signifikan penguras baterai aplikasi Anda.

Pengguna peduli terhadap konsumsi daya baterai karena lebih suka menggunakan perangkat seluler tanpa menghubungkannya ke pengisi daya. Pengguna juga peduli terhadap penggunaan data, karena setiap bit data yang ditransfer bisa menghabiskan biaya.

Dalam bab ini, Anda mempelajari cara aktivitas jaringan di aplikasi memengaruhi perangkat keras radio di perangkat sehingga Anda bisa meminimalkan konsumsi daya baterai yang terkait dengan aktivitas jaringan. Anda juga akan mempelajari cara menunggu kondisi yang tepat untuk menyelesaikan tugas yang banyak menggunakan sumber daya.

Keadaan radio nirkabel

Radio nirkabel yang sepenuhnya aktif mengonsumsi daya yang signifikan. Untuk menghemat daya saat tidak digunakan, radio akan beralih di antara beberapa keadaan energi. Akan tetapi, ada konsekuensi antara penghematan daya dan waktu yang dibutuhkan untuk menyalakan bila diperlukan.

Untuk jaringan 3G pada umumnya, radio memiliki tiga keadaan energi:

  1. Daya penuh: Digunakan bila koneksi aktif. Memungkinkan perangkat mentransfer data dengan kecepatan tertinggi.
  2. Daya rendah: Status menengah yang menggunakan baterai kurang dari 50%.
  3. Siaga: Keadaan energi minimum, selama tidak ada koneksi jaringan yang aktif atau dibutuhkan.

Walaupun keadaan rendah dan siaga menggunakan baterai lebih sedikit, keadaan tersebut juga menimbulkan latensi pada permintaan jaringan. Kembali ke daya penuh dari keadaan rendah memerlukan waktu sekitar 1,5 detik, sedangkan beralih dari siaga ke penuh bisa memerlukan waktu lebih dari 2 detik.

Android menggunakan mesin keadaan untuk menentukan cara transisi antar keadaan. Untuk meminimalkan latensi, mesin keadaan akan menunggu sebentar sebelum transisi ke keadaan energi yang lebih rendah. Transisi radio untuk mesin keadaan nirkabel 3G

Mesin keadaan radio pada setiap perangkat, khususnya penundaan transisi terkait ("waktu ekor") dan latensi startup, bervariasi berdasarkan teknologi radio nirkabel yang digunakan (2G, 3G, LTE, dll.) dan didefinisikan serta dikonfigurasi oleh jaringan operator yang digunakan perangkat untuk beroperasi.

Bab ini menjelaskan mesin keadaan representatif untuk radio nirkabel 3G pada umumnya, berdasarkan data yang disediakan oleh AT&T. Akan tetapi, prinsip umum dan praktik terbaik yang dihasilkan berlaku untuk semua implementasi radio nirkabel.

Seperti halnya praktik terbaik, ada konsekuensi yang perlu dipertimbangkan untuk development aplikasi Anda sendiri.

Membundel transfer jaringan

Setiap kali Anda membuat koneksi jaringan baru, radio akan bertransisi ke keadaan daya penuh. Dalam kasus mesin keadaan radio 3G yang dijelaskan di atas, keadaan akan tetap pada daya penuh selama transfer, diikuti dengan 5 detik waktu ekor, diikuti dengan 12 detik pada keadaan energi rendah sebelum dimatikan. Jadi, untuk perangkat 3G umum, setiap sesi transfer data menyebabkan radio mengonsumsi daya selama hampir 20 detik.

Maksudnya dalam praktik:

  • Aplikasi yang mentransfer data yang tidak dibundel selama 1 detik setiap 18 detik akan membuat radio nirkabel selalu aktif.
  • Sebagai perbandingan, aplikasi serupa yang membundel transfer selama 3 detik setiap menit akan membuat radio dalam keadaan daya tinggi hanya selama 8 detik, dan dalam keadaan daya rendah selama 12 detik lagi.

Contoh kedua memungkinkan radio dalam keadaan diam selama 40 detik setiap menitnya, yang menghasilkan pengurangan besar dalam konsumsi daya baterai. Penggunaan daya radio nirkabel relatif untuk transfer yang dibundel dibandingkan transfer yang tidak dibundel

Membundel dan mengantre transfer data Anda adalah hal penting. Anda bisa membundel transfer yang dijadwalkan terjadi dalam suatu jangka waktu dan membuat semuanya terjadi secara bersamaan, sehingga memastikan radio mengonsumsi daya dalam waktu sesedikit mungkin.

Pemuatan dini

Pemuatan dini untuk data berarti aplikasi Anda akan memperkirakan isi atau data berikutnya yang diinginkan pengguna, dan memuatnya lebih dini. Misalnya, bila pengguna memperhatikan bagian pertama artikel, perkiraan yang baik adalah memuat dini bagian berikutnya. Atau, jika pengguna sedang menonton video, memuat dini menit video berikutnya juga merupakan perkiraan yang baik.

Pemuatan dini atas data adalah cara efektif untuk mengurangi jumlah sesi transfer data independen. Pemuatan dini memungkinkan Anda mengunduh semua data yang mungkin diperlukan untuk jangka waktu tertentu dalam rentetan tunggal, melalui koneksi tunggal, pada kapasitas penuh. Hal ini mengurangi jumlah aktivasi radio yang diperlukan untuk mengunduh data. Akibatnya, Anda tidak hanya menghemat daya tahan baterai, melainkan juga meningkatkan latensi bagi pengguna, mengurangi bandwidth yang diperlukan, dan mengurangi waktu pengunduhan.

Pemuatan dini memiliki konsekuensi. Jika mengunduh terlalu banyak atau data yang salah, Anda bisa menambah konsumsi daya baterai. Dan jika mengunduh pada waktu yang salah, bisa membuat pengguna menunggu. Mengoptimalkan data pemuatan dini merupakan topik tingkat lanjutan yang tidak dibahas dalam kursus ini, namun panduan berikut akan membahas situasi umum.

Seberapa agresif pemuatan dini akan bergantung pada ukuran data yang diunduh dan kemungkinan akan digunakannya. Sebagai panduan kasar, berdasarkan pada mesin keadaan yang dijelaskan di atas, untuk data yang memiliki peluang akan digunakan sebesar 50% dalam sesi pengguna saat ini, Anda biasanya bisa memuat dini selama sekitar 6 detik (sekitar 1-2 Mb) sebelum potensi biaya mengunduh data yang tidak digunakan cocok dengan potensi penghematan dari tidak memulai pengunduhan data itu.

Secara umum, inilah praktik yang baik untuk memuat dini data sehingga Anda hanya perlu memulai pengunduhan lain setiap 2 hingga 5 menit, dan secara berurutan 1 hingga 5 megabyte.

Dengan mengikuti prinsip ini, pengunduhan besar—seperti file video—harus diunduh berupa potongan kecil dengan interval teratur (setiap 2 hingga 5 menit), sehingga pemuatan dini secara efektif hanya untuk data video yang mungkin akan ditampilkan dalam beberapa menit berikutnya.

Contoh pemuatan dini

Banyak aplikasi berita yang berupaya mengurangi bandwidth dengan mengunduh berita utama hanya setelah kategori dipilih, artikel lengkap hanya bila pengguna ingin membacanya, dan gambar kecil sama seperti mereka menggulir ke tampilan.

Dengan menggunakan pendekatan ini, radio dipaksa untuk tetap aktif bagi sebagian besar sesi pembacaan berita saat pengguna menggulir berita utama, mengubah kategori, dan membaca artikel. Tidak hanya itu, namun peralihan terus-menerus di antara keadaan energi mengakibatkan latensi yang signifikan saat beralih kategori atau membaca artikel.

Inilah pendekatan yang lebih baik:

  1. Memuat dini sejumlah data yang wajar pada startup, dimulai dengan serangkaian pertama judul berita dan gambar kecil. Proses ini memastikan waktu startup yang cepat.
  2. Lanjutkan dengan judul berita selebihnya, gambar kecil selebihnya, dan teks artikel untuk setiap artikel dari rangkaian judul berita pertama.

Memantau keadaan konektivitas

Perangkat bisa mengakses jaringan menggunakan tipe perangkat keras yang berbeda:

  • Radio nirkabel menggunakan beragam jumlah daya baterai yang bergantung pada teknologi, dan semakin besar bandwidth semakin banyak konsumsi energi. Bandwidth lebih tinggi berarti Anda bisa memuat dini secara lebih agresif, sehingga mengunduh data lebih banyak dalam waktu yang sama. Akan tetapi, mungkin kurang intuitif, karena biaya baterai waktu ekor relatif lebih tinggi, juga lebih efisien untuk membuat radio tetap aktif dalam jangka waktu yang lebih lama untuk setiap sesi transfer guna mengurangi frekuensi pembaruan.
  • Radio WiFi menggunakan daya baterai jauh lebih sedikit daripada nirkabel dan menawarkan bandwidth yang lebih besar.

Bila memungkinkan, lakukan transfer data saat terhubung melalui Wi-Fi.

Anda bisa menggunakan ConnectivityManager untuk menentukan radio nirkabel yang aktif dan memodifikasi rutinitas pemuatan dini dengan bergantung pada tipe jaringan:

ConnectivityManager cm =
   (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
TelephonyManager tm =
    (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);

NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
int PrefetchCacheSize = DEFAULT_PREFETCH_CACHE;

switch (activeNetwork.getType()) {
    case (ConnectivityManager.TYPE_WIFI):
        PrefetchCacheSize = MAX_PREFETCH_CACHE; break;
    case (ConnectivityManager.TYPE_MOBILE): {
        switch (tm.getNetworkType()) {
           case (TelephonyManager.NETWORK_TYPE_LTE |
                  TelephonyManager.NETWORK_TYPE_HSPAP):
                PrefetchCacheSize *= 4;
                break;
            case (TelephonyManager.NETWORK_TYPE_EDGE |
                  TelephonyManager.NETWORK_TYPE_GPRS):
               PrefetchCacheSize /= 2;
               break;
            default: break;
        }
        break;
      }
  default: break;
  }

Sistem akan mengirimkan maksud siaran bila keadaan konektivitas berubah, sehingga Anda bisa mendengarkan perubahan ini dengan menggunakan BroadcastReceiver.

Memantau keadaan baterai

Untuk meminimalkan konsumsi daya baterai, pantau keadaan baterai dan tunggu kondisi tertentu sebelum memulai operasi yang banyak menggunakan daya baterai.

Dalam hal ini, BatteryManager akan menyiarkan semua detail baterai dan pengisian daya dalam Intent siaran yang menyertakan status pengisian daya.

Untuk memeriksa status baterai saat ini, ujilah maksud siaran:

IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, ifilter);
// Are we charging / charged?
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                     status == BatteryManager.BATTERY_STATUS_FULL;

// How are we charging?
int chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC;

Jika Anda ingin bereaksi terhadap perubahan keadaan pengisian baterai, gunakan BroadcastReceiver yang didaftarkan untuk tindakan status baterai:

<receiver android:name=".PowerConnectionReceiver">
  <intent-filter>
    <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
    <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
  </intent-filter>
</receiver>

Maksud siaran juga dikirim bila level baterai berubah dengan cara signifikan:

"android.intent.action.BATTERY_LOW"
"android.intent.action.BATTERY_OKAY"

JobScheduler

Terus-menerus memantau konektivitas dan status baterai perangkat bisa menjadi suatu tantangan, dan itu mengharuskan penggunaan komponen seperti penerima siaran, yang bisa mengonsumsi sumber daya sistem bahkan bila aplikasi sedang tidak dijalankan. Karena mentransfer data secara efisien merupakan tugas umum, Android SDK menyediakan kelas yang memudahkannya: JobScheduler.

Diperkenalkan dalam API level 21, JobScheduler memungkinkan Anda menjadwalkan tugas dengan ketentuan tertentu (bukan waktu tertentu seperti pada AlarmManager).

JobScheduler memiliki tiga komponen:

  1. JobInfo menggunakan pola builder untuk menyetel ketentuan tugas.
  2. JobService adalah wrapper kelas Service, tempat tugas benar-benar diselesaikan.
  3. JobScheduler menjadwalkan dan membatalkan tugas.
    Catatan: JobScheduler hanya tersedia mulai API 21+. Tidak ada versi kompabilitas mundur untuk sebelum API rilis. Jika aplikasi menargetkan perangkat dengan API level sebelumnya, Anda mungkin akan merasakan manfaat FirebaseJobDispatcher alternatif.

1. JobInfo

Setel ketentuan tugas dengan membuat objek JobInfo menggunakan kelas JobInfo.Builder . Kelas JobInfo.Builder adalah instance yang dibuat dari konstruktor yang membutuhkan dua argumen: ID tugas (yang bisa digunakan untuk membatalkan tugas), dan ComponentName JobService yang berisi tugas. JobInfo.Builder harus menyetel setidaknya satu, ketentuan non-default untuk tugas. Misalnya:

JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
ComponentName serviceName = new ComponentName(getPackageName(),
NotificationJobService.class.getName());
JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, serviceName);
builder.setRequiredNetworkType(NETWORK_TYPE_UNMETERED);
JobInfo jobInfo = builder.build();
Catatan: Lihat praktik terkait untuk contoh lengkap.

Kelas JobInfo.Builder memiliki banyak metode set() yang memungkinkan Anda untuk menentukan ketentuan tugas. Di bawah ini adalah daftar batasan yang tersedia bersama masing-masing metode set() dan kontanta kelasnya:

  • Kebijakan Backoff/Coba Ulang: Menentukan waktu dan cara menjadwalkan ulang tugas jika gagal. Setel ketentuan ini menggunakan metode setBackoffCriteria() , yang menggunakan dua argumen: waktu awal untuk menunggu setelah tugas gagal, dan strategi backoff. Argumen strategi backoff bisa berupa satu dari dua konstanta: BACKOFF_POLICY_LINEAR atau BACKOFF_POLICY_EXPONENTIAL. Default-nya adalah {30 seconds, Exponential}.
  • Latensi Minimum: Jumlah waktu tunggu minimum sebelum menyelesaikan tugas. Setel ketentuan ini menggunakan metode setMinimumLatency() yang memerlukan argumen tunggal: jumlah waktu tunggu dalam milidetik.
  • Ganti Batas Waktu: Waktu tunggu maksimum sebelum menjalankan tugas, bahkan jika ketentuan lain tidak terpenuhi. Setel ketentuan ini menggunakan metode setOverrideDeadline() yang merupakan waktu tunggu maksimum dalam milidetik.
  • Periodik: Mengulangi tugas setelah jumlah waktu tertentu. Setel ketentuan ini menggunakan metode setPeriodic() dengan meneruskan interval pengulangan. Ketentuan ini saling eksklusif dengan latensi minimum dan menggantikan ketentuan batas waktu: menyetel setPeriodic() dengan salah satu ketentuan ini akan mengakibatkan kesalahan.
  • Bertahan: Menyetel apakah tugas dipertahankan saat boot ulang sistem. Agar ketentuan ini bekerja, aplikasi Anda harus memiliki izin RECEIVE_BOOT_COMPLETED . Setel ketentuan ini menggunakan metode setPersisted() dengan meneruskan boolean yang menunjukkan apakah akan mempertahankan tugas atau tidak.
  • Tipe Jaringan yang Diperlukan: Tipe jaringan yang diperlukan tugas Anda. Jika jaringan tidak diperlukan, Anda tidak perlu memanggil fungsi ini, karena default-nya adalah NETWORK_TYPE_NONE. Setel ketentuan ini menggunakan metode setRequiredNetworkType() dengan meneruskan salah satu konstanta berikut: NETWORK_TYPE_NONE, NETWORK_TYPE_ANY, NETWORK_TYPE_NOT_ROAMING, NETWORK_TYPE_UNMETERED.
  • Keadaan Pengisian Daya yang Diperlukan: Apakah steker perangkat perlu dihubungkan atau tidak untuk menjalankan tugas ini. Setel ketentuan ini menggunakan metode setRequiresCharging() dengan meneruskan boolean. Default-nya adalah false.
  • Mengharuskan Perangkat Diam: Apakah perangkat harus dalam mode diam untuk menjalankan tugas ini. "Mode diam" berarti perangkat tidak digunakan dan belum digunakan selama beberapa waktu, seperti yang didefinisikan secara bebas oleh sistem. Bila perangkat dalam mode diam, inilah waktu yang tepat untuk menjalankan tugas yang banyak menggunakan sumber daya. Setel ketentuan ini menggunakan metode setRequiresDeviceIdle() dengan meneruskan boolean. Default-nya adalah false.

2. JobService

Setelah ketentuan tugas terpenuhi, kerangka kerja akan meluncurkan subkelas JobService, yang merupakan tempat Anda mengimplementasikan tugas itu sendiri. JobService berjalan pada thread UI, sehingga Anda perlu memindahkan operasi pemblokiran ke thread pekerja.

Deklarasikan subkelas JobService di Manifes Android, dan sertakan izin BIND_JOB_SERVICE :

<service android:name="MyJobService"
              android:permission="android.permission.BIND_JOB_SERVICE" />

Di subkelas JobServiceAnda, gantikan kedua metode, onStartJob() dan onStopJob().

onStartJob()

Sistem akan memanggil onStartJob() dan secara otomatis meneruskan sebuah objek JobParameters , yang dibuat sistem dengan informasi tentang tugas Anda. Jika tugas Anda berisi operasi yang berjalan lama, pindahkan pekerjaan ke thread terpisah. Metode onStartJob() mengembalikan boolean: true jika tugas sudah dipindahkan ke thread terpisah (artinya mungkin belum selesai) dan false jika tidak ada tugas lain yang harus diselesaikan.

Gunakan metode jobFinished() dari thread apa pun untuk memberi tahu sistem bahwa tugas Anda selesai. Metode ini memerlukan dua parameter: objek JobParameters yang berisi informasi tentang tugas, dan boolean yang menunjukkan apakah tugas perlu dijadwal ulang, sesuai dengan kebijakan backoff yang didefinisikan.

onStopJob()

Sistem akan memanggil onStopJob() jika ini menentukan bahwa Anda harus menghentikan eksekusi tugas bahkan sebelum Anda memanggil jobFinished(). Ini terjadi jika persyaratan yang Anda tetapkan saat menjadwalkan tugas tidak lagi dipenuhi.

Contoh:

  • Jika Anda meminta WiFi dengan setRequiredNetworkType() namun pengguna menonaktifkan WiFi sewaktu tugas dieksekusi, maka sistem akan memanggil onStopJob().
  • Jika Anda menetapkan setRequiresDeviceIdle() namun pengguna mulai berinteraksi dengan perangkat sewaktu tugas dieksekusi, maka sistem akan memanggil onStopJob().

Anda bertanggung jawab atas perilaku aplikasi saat menerima onStopJob(), jadi jangan abaikan. Metode ini mengembalikan boolean, yang menunjukkan apakah Anda ingin menjadwal ulang tugas berdasarkan kebijakan backoff yang didefinisikan, atau melepaskan tugas.

3. JobScheduler

Bagian akhir penjadwalan tugas adalah menggunakan kelas JobScheduler untuk menjadwalkan tugas. Untuk mendapatkan instance kelas ini, panggil getSystemService(JOB_SCHEDULER_SERVICE). Kemudian jadwalkan tugas menggunakan metode schedule() , dengan meneruskan objek JobInfo yang Anda buat dengan JobInfo.Builder. Misalnya:

mScheduler.schedule(myJobInfo);

Kerangka kerja tahu tentang kapan Anda menerima callback, dan mencoba untuk menggabung dan menangguhkannya sebanyak mungkin. Biasanya, jika Anda tidak menetapkan batas waktu tugas, sistem bisa menjalankannya kapan saja, bergantung pada keadaan saat ini dari antrean internal objek JobScheduler ; akan tetapi, mungkin akan ditangguhkan hingga saat berikutnya perangkat dihubungkan ke sumber daya.

Untuk membatalkan tugas, panggil cancel(), dengan meneruskan ID tugas dari objek JobInfo.Builder , atau panggil cancelAll(). Misalnya:

mScheduler.cancelAll();

Praktik terkait

Latihan terkait dan dokumentasi praktik ada di Dasar-Dasar Developer Android: Praktik.

Ketahui selengkapnya

results matching ""

    No results matching ""